/*********************************************************************
*
* CVI Example program:
*    ContAcq-IntClk.c
*
* Example Category:
*    AI
*
* Description:
*    This example demonstrates how to acquire a continuous amount of
*    data using the DAQ device's internal clock.
*
* Instructions for Running:
*    1. Select the physical channel to correspond to where your
*       signal is input on the DAQ device.
*    2. Enter the minimum and maximum voltage range.
*    Note: For better accuracy try to match the input range to the
*          expected voltage level of the measured signal.
*    3. Set the rate of the acquisition. Also set the Samples per
*       Channel control. This will determine how many samples are
*       read at a time. This also determines how many points are
*       plotted on the graph each time.
*    Note: The rate should be at least twice as fast as the maximum
*          frequency component of the signal being acquired.
*
* Steps:
*    1. Create a task.
*    2. Create an analog input voltage channel.
*    3. Set the rate for the sample clock. Additionally, define the
*       sample mode to be continuous.
*    4. Call the Start function to start the acquistion.
*    5. Read the data in the EveryNCallback function until the stop
*       button is pressed or an error occurs.
*    6. Call the Clear Task function to clear the task.
*    7. Display an error if any.
*
* I/O Connections Overview:
*    Make sure your signal input terminal matches the Physical
*    Channel I/O control. For further connection information, refer
*    to your hardware reference manual.
*
*********************************************************************/

#include <stdlib.h>
#include <cvirte.h>
#include <userint.h>
#include <math.h>
#include <NIDAQmx.h>
#include <DAQmxIOctrl.h>
#include "ContAcq-IntClk.h"
#define DAQmxErrChk(functionCall) if( DAQmxFailed(error=(functionCall)) ) goto Error; else

static int	panelHandle;

int samplesToRead = 0;
int samplesReaded = 0;

static TaskHandle	gTaskHandle=0;
static float64		*gData=NULL;
static uInt32		gNumChannels;

int32 CVICALLBACK EveryNCallback(TaskHandle taskHandle, int32 everyNsamplesEventType, uInt32 nSamples, void *callbackData);
int32 CVICALLBACK DoneCallback(TaskHandle taskHandle, int32 status, void *callbackData);

int main(int argc, char *argv[])
{
	if( InitCVIRTE(0,argv,0)==0 )
		return -1;	/* out of memory */
	if( (panelHandle=LoadPanel(0,"ContAcq-IntClk.uir",PANEL))<0 )
		return -1;
	SetCtrlAttribute(panelHandle,PANEL_DECORATION_BLUE,ATTR_FRAME_COLOR,VAL_BLUE);
	SetCtrlAttribute(panelHandle,PANEL_DECORATION_GREEN,ATTR_FRAME_COLOR,VAL_GREEN);
	NIDAQmx_NewPhysChanAICtrl(panelHandle,PANEL_CHANNEL,1);
	DisplayPanel(panelHandle);
	RunUserInterface();
	if( gTaskHandle )
		DAQmxClearTask(gTaskHandle);
	DiscardPanel(panelHandle);
	return 0;
}

int CVICALLBACK PanelCallback(int panel, int event, void *callbackData, int eventData1, int eventData2)
{
	if( event==EVENT_CLOSE )
		QuitUserInterface(0);
	return 0;
}

int CVICALLBACK RangeCallback(int panel, int control, int event, void *callbackData, int eventData1, int eventData2)
{
	if( event==EVENT_COMMIT ) {
		double  min,max;

		GetCtrlVal(panel,PANEL_MINVAL,&min);
		GetCtrlVal(panel,PANEL_MAXVAL,&max);
		if( min<max )
			SetAxisScalingMode(panel,PANEL_STRIPCHART,VAL_LEFT_YAXIS,VAL_MANUAL,min,max);
		return 1;
	}
	return 0;
}

int CVICALLBACK StartCallback(int panel, int control, int event, void *callbackData, int eventData1, int eventData2)
{
	int32       error=0;
	char        chan[256];
	uInt32      sampsPerChan;
	float64     min,max,rate;
	int         log;
	char        errBuff[2048]={'\0'};

	if( event==EVENT_COMMIT ) {
		GetCtrlVal(panel,PANEL_CHANNEL,chan);
		GetCtrlVal(panel,PANEL_MINVAL,&min);
		GetCtrlVal(panel,PANEL_MAXVAL,&max);
		GetCtrlVal(panel,PANEL_RATE,&rate);
		GetCtrlVal(panel,PANEL_SAMPSPERCHAN,&sampsPerChan);
		SetCtrlAttribute(panel,PANEL_STRIPCHART,ATTR_XAXIS_GAIN,1.0/rate);
		log = (int)log10(rate);
		SetCtrlAttribute(panel,PANEL_STRIPCHART,ATTR_XPRECISION,log);
		SetCtrlAttribute(panel,PANEL_STRIPCHART,ATTR_POINTS_PER_SCREEN,sampsPerChan);

		/*********************************************/
		// DAQmx Configure Code
		/*********************************************/
		SetWaitCursor(1);
		DAQmxErrChk (DAQmxCreateTask("",&gTaskHandle));
		DAQmxErrChk (DAQmxCreateAIVoltageChan(gTaskHandle,chan,"",DAQmx_Val_Cfg_Default,min,max,DAQmx_Val_Volts,NULL));
		DAQmxErrChk (DAQmxCfgSampClkTiming(gTaskHandle,"",rate,DAQmx_Val_Rising,DAQmx_Val_ContSamps,sampsPerChan));
		DAQmxErrChk (DAQmxGetTaskAttribute(gTaskHandle,DAQmx_Task_NumChans,&gNumChannels));
		
		samplesToRead = 10 * rate;

		if( (gData=(float64*)malloc(sampsPerChan*gNumChannels*sizeof(float64)))==NULL ) {
			MessagePopup("Error","Not enough memory");
			goto Error;
		}

		DAQmxErrChk (DAQmxRegisterEveryNSamplesEvent(gTaskHandle,DAQmx_Val_Acquired_Into_Buffer,sampsPerChan,0,EveryNCallback,NULL));
		DAQmxErrChk (DAQmxRegisterDoneEvent(gTaskHandle,0,DoneCallback,NULL));

		/*********************************************/
		// DAQmx Start Code
		/*********************************************/
		DAQmxErrChk (DAQmxStartTask(gTaskHandle));

		SetCtrlAttribute(panel,PANEL_STRIPCHART,ATTR_NUM_TRACES,gNumChannels);
		SetCtrlAttribute(panel,PANEL_START,ATTR_DIMMED,1);
	}

Error:
	SetWaitCursor(0);
	if( DAQmxFailed(error) ) {
		DAQmxGetExtendedErrorInfo(errBuff,2048);
		if( gTaskHandle!=0 ) {
			/*********************************************/
			// DAQmx Stop Code
			/*********************************************/
			DAQmxStopTask(gTaskHandle);
			DAQmxClearTask(gTaskHandle);
			gTaskHandle = 0;
			if( gData ) {
				free(gData);
				gData = NULL;
			}
			SetCtrlAttribute(panel,PANEL_START,ATTR_DIMMED,0);
		}
		MessagePopup("DAQmx Error",errBuff);
	}
	return 0;
}

int CVICALLBACK StopCallback(int panel, int control, int event, void *callbackData, int eventData1, int eventData2)
{
	if( event==EVENT_COMMIT && gTaskHandle ) {
		DAQmxStopTask(gTaskHandle);
		DAQmxClearTask(gTaskHandle);
		gTaskHandle = 0;
		if( gData ) {
			free(gData);
			gData = NULL;
		}
		SetCtrlAttribute(panel,PANEL_START,ATTR_DIMMED,0);
	}
	return 0;
}

int32 CVICALLBACK EveryNCallback(TaskHandle taskHandle, int32 everyNsamplesEventType, uInt32 nSamples, void *callbackData)
{
	int32   error=0;
	char    errBuff[2048]={'\0'};
	int     numRead;
	

	/*********************************************/
	// DAQmx Read Code
	/*********************************************/
	DAQmxErrChk (DAQmxReadAnalogF64(taskHandle,nSamples,10.0,DAQmx_Val_GroupByScanNumber,gData,nSamples*gNumChannels,&numRead,NULL));
	if( numRead>0 )
	{
		PlotStripChart(panelHandle,PANEL_STRIPCHART,gData,numRead*gNumChannels,0,0,VAL_DOUBLE);
		
		samplesReaded += numRead;
		if(samplesReaded >= samplesToRead)
		{
			DAQmxStopTask(gTaskHandle);
		    DAQmxClearTask(gTaskHandle);
		    gTaskHandle = 0;
			SetCtrlAttribute(panelHandle,PANEL_START,ATTR_DIMMED,0);
			samplesReaded = 0;
		}
	}

Error:
	if( DAQmxFailed(error) ) {
		DAQmxGetExtendedErrorInfo(errBuff,2048);
		/*********************************************/
		/*/ DAQmx Stop Code
		/*********************************************/
		DAQmxStopTask(taskHandle);
		DAQmxClearTask(taskHandle);
		gTaskHandle = 0;
		if( gData ) {
			free(gData);
			gData = NULL;
		}
		MessagePopup("DAQmx Error",errBuff);
		SetCtrlAttribute(panelHandle,PANEL_START,ATTR_DIMMED,0);
	}
	return 0;
}

int32 CVICALLBACK DoneCallback(TaskHandle taskHandle, int32 status, void *callbackData)
{
	int32   error=0;
	char    errBuff[2048]={'\0'};

	if( gData ) {
		free(gData);
		gData = NULL;
	}
	gTaskHandle = 0;
	// Check to see if an error stopped the task.
	DAQmxErrChk (status);

Error:
	DAQmxGetExtendedErrorInfo(errBuff,2048);
	DAQmxClearTask(taskHandle);
	if( DAQmxFailed(error) )
		MessagePopup("DAQmx Error",errBuff);
	SetCtrlAttribute(panelHandle,PANEL_START,ATTR_DIMMED,0);
	return 0;
}


